home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Linux Cubed Series 7: Sunsite
/
Linux Cubed Series 7 - Sunsite Vol 1.iso
/
system
/
shells
/
zsh-3.0-p
/
zsh-3
/
zsh-3.0-pre3
/
Src
/
lex.c
< prev
next >
Wrap
C/C++ Source or Header
|
1996-07-14
|
26KB
|
1,317 lines
/*
* $Id: lex.c,v 2.35 1996/07/13 20:26:35 hzoli Exp $
*
* lex.c - lexical analysis
*
* This file is part of zsh, the Z shell.
*
* Copyright (c) 1992-1996 Paul Falstad
* All rights reserved.
*
* Permission is hereby granted, without written agreement and without
* license or royalty fees, to use, copy, modify, and distribute this
* software and its documentation for any purpose, provided that the
* above copyright notice and the following two paragraphs appear in
* all copies of this software.
*
* In no event shall Paul Falstad or the Zsh Development Group be liable
* to any party for direct, indirect, special, incidental, or consequential
* damages arising out of the use of this software and its documentation,
* even if Paul Falstad and the Zsh Development Group have been advised of
* the possibility of such damage.
*
* Paul Falstad and the Zsh Development Group specifically disclaim any
* warranties, including, but not limited to, the implied warranties of
* merchantability and fitness for a particular purpose. The software
* provided hereunder is on an "as is" basis, and Paul Falstad and the
* Zsh Development Group have no obligation to provide maintenance,
* support, updates, enhancements, or modifications.
*
*/
#include "zsh.h"
/* lexical state */
static int dbparens;
int len = 0, bsiz = 256;
char *bptr;
extern int hwgetword;
struct lexstack {
struct lexstack *next;
int incmdpos;
int incond;
int incasepat;
int dbparens;
int alstat;
int isfirstln;
int isfirstch;
int histremmed;
int histdone;
int spaceflag;
int stophist;
int hlinesz;
char *hline;
char *hptr;
int tok;
int isnewlin;
char *tokstr;
char *yytext;
char *bptr;
int bsiz;
short *chwords;
int chwordlen;
int chwordpos;
int hwgetword;
struct heredocs *hdocs;
unsigned char *cstack;
int csp;
};
static struct lexstack *lstack = NULL;
/* History word status variables from hist.c */
extern short *chwords;
extern int chwordlen, chwordpos;
/* save the lexical state */
/* is this a hack or what? */
/**/
void
lexsave(void)
{
struct lexstack *ls;
DPUTS(alstackind, "BUG: lexsave called with alstackind != 0");
ls = (struct lexstack *)malloc(sizeof(struct lexstack));
ls->incmdpos = incmdpos;
ls->incond = incond;
ls->incasepat = incasepat;
ls->dbparens = dbparens;
ls->alstat = alstat;
ls->isfirstln = isfirstln;
ls->isfirstch = isfirstch;
ls->histremmed = histremmed;
ls->histdone = histdone;
ls->spaceflag = spaceflag;
ls->stophist = stophist;
ls->hline = chline;
ls->hptr = hptr;
ls->hlinesz = hlinesz;
ls->cstack = cmdstack;
ls->csp = cmdsp;
cmdstack = (unsigned char *)zalloc(256);
ls->tok = tok;
ls->isnewlin = isnewlin;
ls->tokstr = tokstr;
ls->yytext = yytext;
ls->bptr = bptr;
ls->bsiz = bsiz;
ls->chwords = chwords;
ls->chwordlen = chwordlen;
ls->chwordpos = chwordpos;
ls->hwgetword = hwgetword;
ls->hdocs = hdocs;
cmdsp = 0;
inredir = 0;
hdocs = NULL;
ls->next = lstack;
lstack = ls;
}
/* restore lexical state */
/**/
void
lexrestore(void)
{
struct lexstack *ln;
if (!lstack) {
zerr("lexrestore without lexsave", NULL, 0);
return;
}
incmdpos = lstack->incmdpos;
incond = lstack->incond;
incasepat = lstack->incasepat;
dbparens = lstack->dbparens;
alstat = lstack->alstat;
isfirstln = lstack->isfirstln;
isfirstch = lstack->isfirstch;
histremmed = lstack->histremmed;
histdone = lstack->histdone;
spaceflag = lstack->spaceflag;
stophist = lstack->stophist;
chline = lstack->hline;
hptr = lstack->hptr;
if (cmdstack)
free(cmdstack);
cmdstack = lstack->cstack;
cmdsp = lstack->csp;
tok = lstack->tok;
isnewlin = lstack->isnewlin;
tokstr = lstack->tokstr;
yytext = lstack->yytext;
bptr = lstack->bptr;
bsiz = lstack->bsiz;
chwords = lstack->chwords;
chwordlen = lstack->chwordlen;
chwordpos = lstack->chwordpos;
hwgetword = lstack->hwgetword;
hdocs = lstack->hdocs;
clearalstack();
hlinesz = lstack->hlinesz;
lexstop = errflag = 0;
ln = lstack->next;
free(lstack);
lstack = ln;
}
/**/
void
yylex(void)
{
if (tok == LEXERR)
return;
do
tok = gettok();
while (tok != ENDINPUT && exalias());
if (tok == NEWLIN || tok == ENDINPUT) {
while (hdocs) {
struct heredocs *next = hdocs->next;
hwbegin(0);
cmdpush(hdocs->rd->type == HEREDOC ? CS_HEREDOC : CS_HEREDOCD);
STOPHIST
hdocs->rd->name = gethere(hdocs->rd->name, hdocs->rd->type);
ALLOWHIST
cmdpop();
hwend();
hdocs->rd->type = HERESTR;
zfree(hdocs, sizeof(struct heredocs));
hdocs = next;
}
}
if (tok != NEWLIN)
isnewlin = 0;
else
isnewlin = (inbufct) ? -1 : 1;
if (tok == SEMI || tok == NEWLIN)
tok = SEPER;
}
/**/
void
ctxtlex(void)
{
static int oldpos;
yylex();
switch (tok) {
case SEPER:
case NEWLIN:
case SEMI:
case DSEMI:
case AMPER:
case AMPERBANG:
case INPAR:
case INBRACE:
case DBAR:
case DAMPER:
case BAR:
case BARAMP:
case INOUTPAR:
case DO:
case THEN:
case ELIF:
case ELSE:
case DOUTBRACK:
incmdpos = 1;
break;
case STRING:
/* case ENVSTRING: */
case ENVARRAY:
case OUTPAR:
case CASE:
case DINBRACK:
incmdpos = 0;
break;
}
if (IS_REDIROP(tok) || tok == FOR || tok == FOREACH || tok == SELECT) {
inredir = 1;
oldpos = incmdpos;
incmdpos = 0;
} else if (inredir) {
incmdpos = oldpos;
inredir = 0;
}
}
#define LX1_BKSLASH 0
#define LX1_COMMENT 1
#define LX1_NEWLIN 2
#define LX1_SEMI 3
#define LX1_AMPER 5
#define LX1_BAR 6
#define LX1_INPAR 7
#define LX1_OUTPAR 8
#define LX1_INANG 13
#define LX1_OUTANG 14
#define LX1_OTHER 15
#define LX2_BREAK 0
#define LX2_OUTPAR 1
#define LX2_BAR 2
#define LX2_STRING 3
#define LX2_INBRACK 4
#define LX2_OUTBRACK 5
#define LX2_TILDE 6
#define LX2_INPAR 7
#define LX2_INBRACE 8
#define LX2_OUTBRACE 9
#define LX2_OUTANG 10
#define LX2_INANG 11
#define LX2_EQUALS 12
#define LX2_BKSLASH 13
#define LX2_QUOTE 14
#define LX2_DQUOTE 15
#define LX2_BQUOTE 16
#define LX2_COMMA 17
#define LX2_OTHER 18
#define LX2_META 19
unsigned char lexact1[256], lexact2[256], lextok2[256];
/**/
void
initlextabs(void)
{
int t0;
static char *lx1 = "\\q\n;!&|(){}[]<>";
static char *lx2 = ";)|$[]~({}><=\\\'\"`,";
for (t0 = 0; t0 != 256; t0++) {
lexact1[t0] = LX1_OTHER;
lexact2[t0] = LX2_OTHER;
lextok2[t0] = t0;
}
for (t0 = 0; lx1[t0]; t0++)
lexact1[(int)lx1[t0]] = t0;
for (t0 = 0; lx2[t0]; t0++)
lexact2[(int)lx2[t0]] = t0;
lexact2['&'] = LX2_BREAK;
lexact2[STOUC(Meta)] = LX2_META;
lextok2['*'] = Star;
lextok2['?'] = Quest;
lextok2['{'] = Inbrace;
lextok2['['] = Inbrack;
lextok2['$'] = String;
lextok2['~'] = Tilde;
}
/* initialize lexical state */
/**/
void
lexinit(void)
{
incond = incasepat = nocorrect =
dbparens = alstat = lexstop = 0;
incmdpos = 1;
tok = ENDINPUT;
if (isset(EXTENDEDGLOB)) {
lextok2['#'] = Pound;
lextok2['^'] = Hat;
} else {
lextok2['#'] = '#';
lextok2['^'] = '^';
}
}
/* add a char to the string buffer */
/**/
void
add(int c)
{
*bptr++ = c;
if (bsiz == ++len) {
int newbsiz;
newbsiz = bsiz * 8;
while (newbsiz < inbufct)
newbsiz *= 2;
bptr = len + (tokstr = (char *)hrealloc(tokstr, bsiz, newbsiz));
bsiz = newbsiz;
}
}
#define SETPARBEGIN {if (zleparse && !alstackind && cs >= ll+1-inbufct) parbegin = inbufct;}
#define SETPAREND {\
if (zleparse && !alstackind && parbegin != -1 && parend == -1)\
if (cs >= ll + 1 - inbufct)\
parbegin = -1;\
else\
parend = inbufct;}
/**/
int
gettok(void)
{
int c, d;
int peekfd = -1, peek;
MUSTUSEHEAP("gettok");
beginning:
tokstr = NULL;
while (iblank(c = hgetc()) && !lexstop);
isfirstln = 0;
wordbeg = inbufct - (qbang && c == bangchar);
hwbegin(-1); /* word includes the last character read */
if (dbparens) {
len = 0;
bptr = tokstr = (char *)ncalloc(bsiz = 256);
hungetc(c);
cmdpush(CS_MATH);
c = dquote_parse(')', 0);
cmdpop();
if (c || (c = hgetc()) != ')') {
hungetc(c);
*bptr = '\0';
return LEXERR;
}
dbparens = 0;
*bptr = '\0';
return DOUTPAR;
} else if (idigit(c)) { /* handle 1< foo */
d = hgetc();
hungetc(d);
lexstop = 0;
if (d == '>' || d == '<') {
peekfd = c - '0';
c = hgetc();
}
}
/* chars in initial position in word */
if (c == hashchar &&
(isset(INTERACTIVECOMMENTS) ||
(!zleparse && !expanding &&
(!interact || unset(SHINSTDIN) || strin)))) {
/* History is handled here to prevent extra *
* newlines being inserted into the history. */
while ((c = ingetc()) != '\n' && !lexstop) {
hwaddc(c);
addtoline(c);
}
if (errflag)
peek = LEXERR;
else {
hwend();
hwbegin(0);
hwaddc('\n');
addtoline('\n');
peek = NEWLIN;
}
return peek;
}
if (lexstop)
return (errflag) ? LEXERR : ENDINPUT;
switch (lexact1[STOUC(c)]) {
case LX1_BKSLASH:
d = hgetc();
if (d == '\n')
goto beginning;
hungetc(d);
lexstop = 0;
break;
case LX1_NEWLIN:
return NEWLIN;
case LX1_SEMI:
d = hgetc();
if (d != ';') {
hungetc(d);
lexstop = 0;
return SEMI;
}
return DSEMI;
case LX1_AMPER:
d = hgetc();
if (d == '&')
return DAMPER;
else if (d == '!' || d == '|')
return AMPERBANG;
else if (d == '>') {
d = hgetc();
if (d == '!' || d == '|')
return OUTANGAMPBANG;
else if (d == '>') {
d = hgetc();
if (d == '!' || d == '|')
return DOUTANGAMPBANG;
hungetc(d);
lexstop = 0;
return DOUTANGAMP;
}
hungetc(d);
lexstop = 0;
return AMPOUTANG;
}
hungetc(d);
lexstop = 0;
return AMPER;
case LX1_BAR:
d = hgetc();
if (d == '|')
return DBAR;
else if (d == '&')
return BARAMP;
hungetc(d);
lexstop = 0;
return BAR;
case LX1_INPAR:
d = hgetc();
if (d == '(' && incmdpos) {
dbparens = 1;
return DINPAR;
} else if (d == ')')
return INOUTPAR;
hungetc(d);
lexstop = 0;
if (!(incond == 1 || incmdpos))
break;
return INPAR;
case LX1_OUTPAR:
return OUTPAR;
case LX1_INANG:
d = hgetc();
if ((!incmdpos && d == '(') || incasepat) {
hungetc(d);
lexstop = 0;
break;
}
if (d == '>')
peek = INOUTANG;
else if (idigit(d) || d == '-') {
int tbs = 256, n = 0, nc;
char *tbuf, *tbp, *ntb;
tbuf = tbp = (char *)zalloc(tbs);
hungetc(d);
while ((nc = hgetc()) && !lexstop) {
if (!idigit(nc) && nc != '-')
break;
*tbp++ = (char)nc;
if (++n == tbs) {
ntb = (char *)realloc(tbuf, tbs *= 2);
tbp += ntb - tbuf;
tbuf = ntb;
}
}
if (nc == '>' && !lexstop) {
hungetc(nc);
while (n--)
hungetc(*--tbp);
zfree(tbuf, tbs);
break;
}
if (nc && !lexstop)
hungetc(nc);
lexstop = 0;
while (n--)
hungetc(*--tbp);
zfree(tbuf, tbs);
peek = INANG;
} else if (d == '<') {
int e = hgetc();
if (e == '(') {
hungetc(e);
hungetc(d);
peek = INANG;
} else if (e == '<')
peek = TRINANG;
else if (e == '-')
peek = DINANGDASH;
else {
hungetc(e);
lexstop = 0;
peek = DINANG;
}
} else if (d == '&')
peek = INANGAMP;
else {
peek = INANG;
hungetc(d);
lexstop = 0;
}
tokfd = peekfd;
return peek;
case LX1_OUTANG:
d = hgetc();
if (d == '(') {
hungetc(d);
break;
} else if (d == '&') {
d = hgetc();
if (d == '!' || d == '|')
peek = OUTANGAMPBANG;
else {
hungetc(d);
lexstop = 0;
peek = OUTANGAMP;
}
} else if (d == '!' || d == '|')
peek = OUTANGBANG;
else if (d == '>') {
d = hgetc();
if (d == '&') {
d = hgetc();
if (d == '!' || d == '|')
peek = DOUTANGAMPBANG;
else {
hungetc(d);
lexstop = 0;
peek = DOUTANGAMP;
}
} else if (d == '!' || d == '|')
peek = DOUTANGBANG;
else if (d == '(') {
hungetc(d);
hungetc('>');
peek = OUTANG;
} else {
hungetc(d);
lexstop = 0;
peek = DOUTANG;
if (isset(HISTALLOWCLOBBER))
hwaddc('|');
}
} else {
hungetc(d);
lexstop = 0;
peek = OUTANG;
if (!incond && isset(HISTALLOWCLOBBER))
hwaddc('|');
}
tokfd = peekfd;
return peek;
}
/* we've started a string, now get the *
* rest of it, performing tokenization */
return gettokstr(c, 0);
}
/**/
int
gettokstr(int c, int sub)
{
int bct = 0, pct = 0, brct = 0;
int intpos = 1, in_brace_param = 0;
int peek, inquote;
#ifdef DEBUG
int ocmdsp = cmdsp;
#endif
peek = STRING;
if (!sub) {
len = 0;
bptr = tokstr = (char *)ncalloc(bsiz = 256);
}
for (;;) {
int act;
int e;
if (inblank(c) && !in_brace_param && !pct)
act = LX2_BREAK;
else {
act = lexact2[STOUC(c)];
c = lextok2[STOUC(c)];
}
switch (act) {
case LX2_BREAK:
if (!in_brace_param && !sub)
goto brk;
break;
case LX2_META:
c = hgetc();
#ifdef DEBUG
if (lexstop) {
fputs("BUG: input terminated by Meta\n", stderr);
fflush(stderr);
goto brk;
}
#endif
add(Meta);
break;
case LX2_OUTPAR:
if ((sub || in_brace_param) && isset(SHGLOB))
break;
if (!in_brace_param && !pct--)
if (sub) {
pct = 0;
break;
} else
goto brk;
c = Outpar;
break;
case LX2_BAR:
if (!pct && !in_brace_param)
if (sub)
break;
else
goto brk;
if (unset(SHGLOB) || (!sub && !in_brace_param))
c = Bar;
break;
case LX2_STRING:
e = hgetc();
if (e == '[') {
cmdpush(CS_MATHSUBST);
add(String);
add(Inbrack);
c = dquote_parse(']', sub);
cmdpop();
if (c) {
peek = LEXERR;
goto brk;
}
c = Outbrack;
} else if (e == '(') {
add(String);
c = hgetc();
if (c == '(') {
add(Inpar);
add('(');
cmdpush(CS_MATHSUBST);
if (!(c = dquote_parse(')', sub))) {
add(')');
if ((c = hgetc()) == ')')
c = 0;
}
cmdpop();
}
else {
hungetc(c);
lexstop = 0;
c = skipcomm();
}
if (c) {
peek = LEXERR;
goto brk;
}
c = Outpar;
} else {
if (e == '{') {
add(c);
c = Inbrace;
++bct;
cmdpush(CS_BRACEPAR);
if (!in_brace_param)
in_brace_param = bct;
} else {
hungetc(e);
lexstop = 0;
}
}
break;
case LX2_INBRACK:
add(c);
if (!in_brace_param)
brct++;
c = hgetc();
if (c == '!' || c == '^') {
add(c);
c = hgetc();
}
if (c == ']')
break;
if (lexstop)
goto brk;
intpos = 0;
continue;
case LX2_OUTBRACK:
if (brct < 0) {
brct = 0;
break;
}
c = Outbrack;
break;
case LX2_INPAR:
if ((sub || in_brace_param) && isset(SHGLOB))
break;
if (!in_brace_param) {
if (!sub) {
e = hgetc();
hungetc(e);
lexstop = 0;
if (e == ')' ||
(incmdpos && !brct && peek != ENVSTRING))
goto brk;
}
pct++;
}
c = Inpar;
break;
case LX2_INBRACE:
if (isset(IGNOREBRACES) || sub)
c = '{';
else {
if (in_brace_param)
cmdpush(CS_BRACE);
bct++;
}
break;
case LX2_OUTBRACE:
if (!bct || ((isset(IGNOREBRACES) || sub) && !in_brace_param))
break;
if (in_brace_param)
cmdpop();
if (bct-- == in_brace_param)
in_brace_param = 0;
c = Outbrace;
break;
case LX2_COMMA:
if (unset(IGNOREBRACES) && !sub && bct > in_brace_param)
c = Comma;
break;
case LX2_OUTANG:
if (!intpos)
if (in_brace_param || sub)
break;
else
goto brk;
e = hgetc();
if (e != '(') {
hungetc(e);
lexstop = 0;
goto brk;
}
add(Outang);
if (skipcomm()) {
peek = LEXERR;
goto brk;
}
c = Outpar;
break;
case LX2_INANG:
if (isset(SHGLOB) && sub)
break;
e = hgetc();
if (!(idigit(e) || e == '-' || (e == '(' && intpos))) {
hungetc(e);
lexstop = 0;
if (in_brace_param || sub)
break;
goto brk;
}
c = Inang;
if (e == '(') {
add(c);
if (skipcomm()) {
peek = LEXERR;
goto brk;
}
c = Outpar;
} else {
add(c);
c = e;
while (c != '>' && !lexstop)
add(c), c = hgetc();
c = Outang;
}
break;
case LX2_EQUALS:
if (intpos) {
e = hgetc();
if (e != '(') {
hungetc(e);
lexstop = 0;
c = Equals;
} else {
add(Equals);
if (skipcomm()) {
peek = LEXERR;
goto brk;
}
c = Outpar;
}
} else if (!sub && peek != ENVSTRING &&
incmdpos && !bct && !brct) {
e = hgetc();
if (e == '(' && incmdpos) {
*bptr = '\0';
return ENVARRAY;
}
hungetc(e);
lexstop = 0;
peek = ENVSTRING;
intpos = 2;
} else
c = Equals;
break;
case LX2_BKSLASH:
c = hgetc();
if (c == '\n') {
c = hgetc();
if (!lexstop)
continue;
} else
add(Bnull);
if (lexstop)
goto brk;
break;
case LX2_QUOTE:
add(Snull);
cmdpush(CS_QUOTE);
for (;;) {
STOPHIST
while ((c = hgetc()) != '\'' && !lexstop) {
if (!sub && isset(CSHJUNKIEQUOTES) && c == '\n') {
if (bptr[-1] == '\\')
bptr--, len--;
else
break;
}
add(c);
}
ALLOWHIST
if (c != '\'') {
zerr("unmatched \'", NULL, 0);
peek = LEXERR;
cmdpop();
goto brk;
}
e = hgetc();
if (e != '\'' || unset(RCQUOTES))
break;
add(c);
}
cmdpop();
hungetc(e);
lexstop = 0;
c = Snull;
break;
case LX2_DQUOTE:
add(Dnull);
cmdpush(CS_DQUOTE);
c = dquote_parse('"', sub);
cmdpop();
if (c) {
zerr("unmatched \"", NULL, 0);
peek = LEXERR;
goto brk;
}
c = Dnull;
break;
case LX2_BQUOTE:
add(Tick);
cmdpush(CS_BQUOTE);
SETPARBEGIN
inquote = 0;
while ((c = hgetc()) != '`' && !lexstop)
if (c == '\\') {
c = hgetc();
if (c != '\n') {
add(c == '`' || c == '\\' || c == '$' ? Bnull : '\\');
add(c);
}
else if (!sub && isset(CSHJUNKIEQUOTES))
add(c);
} else {
if (!sub && isset(CSHJUNKIEQUOTES) && c == '\n') {
break;
}
add(c);
if (c == '\'')
if ((inquote = !inquote))
STOPHIST
else
ALLOWHIST
}
if (inquote)
ALLOWHIST
cmdpop();
if (c != '`') {
zerr("unmatched `", NULL, 0);
peek = LEXERR;
goto brk;
}
c = Tick;
SETPAREND
break;
}
add(c);
c = hgetc();
if (intpos)
intpos--;
if (lexstop)
break;
}
brk:
hungetc(c);
*bptr = '\0';
DPUTS(cmdsp != ocmdsp, "BUG: gettok: cmdstack changed.");
return peek;
}
extern int addedx;
/**/
int
dquote_parse(char endchar, int sub)
{
int pct = 0, brct = 0, bct = 0, intick = 0, err = 0;
int c;
int math = endchar == ')' || endchar == ']';
int zlemath = math && cs > ll + addedx - inbufct;
while (((c = hgetc()) != endchar || bct ||
(math && ((pct > 0) || (brct > 0))) ||
intick) && !lexstop) {
switch (c) {
case '\\':
c = hgetc();
if (c != '\n')
add(c == '$' || c == '\\' || (c == '}' && !intick && bct) ||
c == '\"' || c == '`' ? Bnull : '\\');
else if (sub || unset(CSHJUNKIEQUOTES) || endchar != '"')
continue;
break;
case '\n':
err = !sub && isset(CSHJUNKIEQUOTES) && endchar == '"';
break;
case '$':
if (intick)
break;
c = hgetc();
if (c == '(') {
add(Qstring);
c = hgetc();
if (c == '(') {
add(Inpar);
add('(');
cmdpush(CS_MATHSUBST);
if (!(err = dquote_parse(')', sub))) {
add(')');
if ((err = hgetc()) == ')')
err = 0;
}
cmdpop();
}
else {
hungetc(c);
lexstop = 0;
err = skipcomm();
}
c = Outpar;
} else if (c == '[') {
add(String);
add(Inbrack);
cmdpush(CS_MATHSUBST);
err = dquote_parse(']', sub);
cmdpop();
c = Outbrack;
} else if (c == '{') {
add(Qstring);
c = Inbrace;
cmdpush(CS_BRACEPAR);
bct++;
} else if (c == '$')
add(Qstring);
else {
hungetc(c);
lexstop = 0;
c = Qstring;
}
break;
case '}':
if (intick || !bct)
break;
c = Outbrace;
bct--;
cmdpop();
break;
case '`':
c = Qtick;
if (intick == 2)
ALLOWHIST
if ((intick = !intick)) {
SETPARBEGIN
cmdpush(CS_BQUOTE);
} else {
SETPAREND
cmdpop();
}
break;
case '\'':
if (!intick)
break;
if (intick == 1)
intick = 2, STOPHIST
else
intick = 1, ALLOWHIST
break;
case '(':
pct++;
break;
case ')':
err = (!pct-- && math);
break;
case '[':
brct++;
break;
case ']':
err = (!brct-- && math);
break;
case '"':
if (intick || !endchar)
break;
if (bct) {
add(Dnull);
err = dquote_parse('"', sub);
c = Dnull;
} else
err = 1;
break;
}
if (err || lexstop)
break;
add(c);
}
if (intick == 2)
ALLOWHIST
if (intick)
cmdpop();
while (bct--)
cmdpop();
if (lexstop)
err = intick || endchar || err;
else if (err == 1)
err = c;
if (zlemath && cs <= ll + 1 - inbufct)
inwhat = IN_MATH;
return err;
}
/* Tokenize a string given in s. Parsing is done as in double *
* quotes. This is usually called before singsub(). */
/**/
int
parsestr(char *s)
{
int l = strlen(s), err;
HEAPALLOC {
lexsave();
untokenize(s);
inpush(dupstring(s), 0);
strinbeg();
stophist = 2;
len = 0;
bptr = tokstr = s;
bsiz = l + 1;
err = dquote_parse('\0', 1);
*bptr = '\0';
strinend();
inpop();
DPUTS(cmdsp, "BUG: parsestr: cmdstack not empty.");
lexrestore();
if (err) {
untokenize(s);
if (err > 32 && err < 127)
zerr("parse error near `%c'", NULL, err);
else
zerr("parse error", NULL, 0);
}
} LASTALLOC;
return err;
}
/* Tokenize a string given in s. Parsing is done as if s were a normal *
* command-line argument but it may contain separators. This is used *
* to parse the right-hand side of ${...%...} substitutions. */
/**/
int
parse_subst_string(char *s)
{
int c, l = strlen(s), err;
if (! *s)
return 0;
lexsave();
untokenize(s);
inpush(dupstring(s), 0);
strinbeg();
stophist = 2;
len = 0;
bptr = tokstr = s;
bsiz = l + 1;
c = hgetc();
c = gettokstr(c, 1);
err = errflag;
strinend();
inpop();
DPUTS(cmdsp, "BUG: parse_subst_string: cmdstack not empty.");
lexrestore();
errflag = err;
if (c == LEXERR) {
untokenize(s);
return 1;
}
#ifdef DEBUG
if (c != STRING || len != l || errflag) {
fprintf(stderr, "Oops. Bug in parse_subst_string: %s\n",
len < l ? "len < l" : errflag ? "errflag" : "c != STRING");
fflush(stderr);
untokenize(s);
return 1;
}
#endif
return 0;
}
/* expand aliases and reserved words */
/**/
int
exalias(void)
{
Alias an;
Reswd rw;
hwend();
if (interact && isset(SHINSTDIN) && !strin && !incasepat &&
tok == STRING && !nocorrect && !alstackind &&
(isset(CORRECTALL) || (isset(CORRECT) && incmdpos)))
spckword(&tokstr, 1, incmdpos, 1);
if (!tokstr) {
yytext = tokstrings[tok];
if (yytext)
yytext = dupstring(yytext);
return 0;
}
if (has_token(tokstr)) {
char *p, *t;
yytext = p = ncalloc(strlen(tokstr) + 1);
for (t = tokstr; (*p++ = itok(*t) ? ztokens[*t++ - Pound] : *t++););
} else
yytext = tokstr;
if (zleparse && !alstackind) {
int zp = zleparse;
gotword();
if (zp && !zleparse) {
return 0;
}
}
/* Check for an alias */
an = noaliases ? NULL : (Alias) aliastab->getnode(aliastab, yytext);
if (alstackind != MAXAL && an && !an->inuse &&
((an->flags & ALIAS_GLOBAL) || incmdpos || alstat == ALSTAT_MORE)) {
an->inuse = 1;
inpush((alstack[alstackind++] = an)->text, INP_ALIAS);
alstat = 0;
/* remove from history if it begins with space */
if (isset(HISTIGNORESPACE) && an->text[0] == ' ')
remhist();
lexstop = 0;
return 1;
}
if (tok == STRING) {
/* Then check for a reserved word */
if ((incmdpos || (tokstr[0] == '}' && !tokstr[1])) &&
(rw = (Reswd) reswdtab->getnode(reswdtab, yytext))) {
tok = rw->token;
if (tok == DINBRACK)
incond = 1;
} else if (incond && !strcmp(yytext, "]]")) {
tok = DOUTBRACK;
incond = 0;
} else if (incond && yytext[0] == '!' && !yytext[1])
tok = BANG;
}
return 0;
}
/* skip (...) */
/**/
int
skipcomm(void)
{
int pct = 1, c;
cmdpush(CS_CMDSUBST);
SETPARBEGIN
c = Inpar;
do {
add(c);
c = hgetc();
if (itok(c) || lexstop)
break;
switch (c) {
case '(':
pct++;
break;
case ')':
pct--;
break;
case '\\':
add(c);
c = hgetc();
break;
case '\'':
add(c);
STOPHIST
while ((c = hgetc()) != '\'' && !lexstop)
add(c);
ALLOWHIST
break;
case '\"':
add(c);
while ((c = hgetc()) != '\"' && !lexstop)
if (c == '\\') {
add(c);
add(hgetc());
} else
add(c);
break;
case '`':
add(c);
while ((c = hgetc()) != '`' && !lexstop)
if (c == '\\')
add(c), add(hgetc());
else
add(c);
break;
}
}
while (pct);
if (!lexstop)
SETPAREND
cmdpop();
return lexstop;
}